home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 5548 < prev    next >
Encoding:
Internet Message Format  |  1996-08-05  |  5.7 KB

  1. Path: dawn.mmm.com!news
  2. From: kjhopps@mmm.com (Kevin J Hopps)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: How to handle error in constructor
  5. Date: 5 Feb 1996 16:12:02 GMT
  6. Organization: 3M - St. Paul, MN  55144-1000 US
  7. Distribution: world
  8. Message-ID: <4f5a8i$hga@dawn.mmm.com>
  9. References: <DLyyIM.5EG@teslab.lab.oz.au> <4eo6n6$rbp@cnn.exu.ericsson.se>
  10. Reply-To: kjhopps@mmm.com
  11. X-Newsreader: TIN [version 1.2 PL2]
  12.  
  13. Walt Howard (walth@netcom.com) wrote:
  14. > On Tue, 30 Jan 1996 00:54:21 GMT, andrew@teslab.lab.oz.au (Andrew
  15. > Phillips) wrote:
  16.  
  17. > >I'm converting and enhancing a simple program in C to C++.  Without going
  18. > >into too much detail I have a class that represents a file on disk.  The
  19. > >contructor opens the file, but what should it do if the file cannot be
  20. > >opened?  The C program just calls fopen() tests the return value and 
  21. > >if there's an error it prints a message and exits.
  22. > >
  23. > >In C++ I thought to set a flag in the constructor and have a member function
  24. > >that tests the flag to see if the file was opened correctly.  This seems
  25. > >rather inelegant -- I guess exceptions would be the elegant way but seem
  26. > >like overkill for such a simple program.  I've looked in several C++ books but
  27. > >error handling is given scant coverage except for exception handling.
  28. > >
  29. > >Any suggestions would be greatly appreciated.
  30. > >
  31.  
  32. > There are several approaches. The one you came up with is similar to
  33. > what the C++ stream library does. However, that was written before
  34. > exceptions were available. 
  35.  
  36. > Exceptions is the only way to go on this. And you shouldn't consider
  37.  
  38. The only way to view statements about "the only way" is with skepticism :-)
  39.  
  40. > them overkill, they really aren't. All you have to say is, for
  41. > example:
  42.  
  43. > try
  44. > {
  45. >     if ( action() == fail )
  46. >         throw( "dang file didn't open" ); 
  47. >             //Here I "throw" a char* pointer
  48. > }
  49. > catch( char* errorMessage ) // and here I catch it and deal with it
  50. > {
  51. >     printf( "%s", errorMessage );
  52. >     exit( -1 ); // or whatever
  53. > }
  54.  
  55. It is unlikely that the catch statement would be in the constructor.
  56. More than likely the catch would be in a piece of code that would
  57. do something about the problem.
  58.  
  59. > Try it a few times and you'll see how simple it is. The books make it
  60. > seem complicated but it isn't. The rewards are well worth it. 
  61.  
  62. Throwing exceptions is easy.  Writing code that behaves correctly
  63. when exceptions are thrown is not always so easy.  A recent issue
  64. of C++ Report discussed many of these potential problems.
  65.  
  66. > Exceptions will reliably trap and clean up a bad construction and I
  67. > recommend using them as such, however there are some other issues
  68. > involved.
  69.  
  70. Exceptions do not clean up anything.  The "stack unwinding" that
  71. is done in propagating an exception from its throw point to its
  72. handler will call the destructors of any automatic (stack based)
  73. objects that have been fully constructed since entry into the
  74. catch's try block.  Any clean up that is done must be done in
  75. those destructors.
  76.  
  77. > From my experience, I would say that any class whose constructor has
  78. > ANY chance to fail, should not do the failure-possible action during
  79. > the constructor. Have a function called init(void) (always void
  80. > argument) that does the actual activation of the object.
  81.  
  82. > Have the constructor do EVERYTHING necessary to prime/lock and load
  83. > the object, but the init( ) function actually pulls the trigger. The
  84. > init() function should just have (void) as an argument because all its
  85. > going to do is pull the trigger right?
  86.  
  87. > For a file object, the construction might set the name and file access
  88. > mode but the init() function would actually OPEN the file.
  89.  
  90. Dividing the initialization into two parts like this is a holdover
  91. from the days before exceptions.  This approach allowed you to
  92. get a return status from object initialization (via the init() func)
  93. while the constructor provided no direct error reporting means.
  94.  
  95. Doing things in this way means that when implementing the class,
  96. you need to keep track of whether init was called.  If one follows
  97. the convention that the constructor throws an exception if it cannot
  98. complete successfully, then the other member functions do not need
  99. to verify that initialization was performed.  (Otherwise there would
  100. be no object on which to call the member function.)
  101.  
  102. Using the construct/init separation also makes it more difficult
  103. to use the class as a member of another class.  If I do this, now
  104. either I have to use the construct/init separation, or I have to
  105. call the init functions of all my member objects that use the
  106. construct/init mechanism.
  107.  
  108. Things get even worse with multiple inheritance.  And with virtual
  109. inheritance you have to be careful that the init() functions of
  110. common base classes are not called more than once.
  111.  
  112. > This has many benefits. For example, if you're object's constructor
  113. > can fail, GLOBAL objects (those constructed at startup time) can fail
  114. > and you can't trap that with an try/catch exception handler. Way
  115. > bummer.
  116.  
  117. This is indeed a problem.  Global objects and exception-throwing
  118. constructors are not a good mix.  However, global objects sometimes are
  119. a problem because of order-of-initialization dependencies, and might be
  120. avoided for a couple of reasons.  One alternative to global objects is
  121. to provide global or public static functions that construct if necessary
  122. and return a reference.  This provides a way to catch exceptions and
  123. avoid order-of-initialization problems.
  124. --
  125. Kevin J. Hopps                  e-mail: kjhopps@mmm.com
  126. 3M Company                      phone:  (612) 737-4643
  127. 3M Center, Bldg. 235-2D-57      fax:    (612) 737-2700
  128. St. Paul, MN 55144-1000         Opinions are my own.  I don't speak for 3M.
  129.     But 3M speaks for me -- I did not write the following line:
  130.  
  131. Opinions expressed herein are my own and may not represent those of 3M.
  132.